// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// i [author] rhyme_lph
// s [email]  rhymelph@gmail.com
// z [github] https://github.com/rhymelph

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/ocr_attachment_entity.dart';
import 'package:finance_app/src/entities/services_entity.dart';
import 'package:finance_app/src/entities/setting_data_entity.dart';
import 'package:finance_app/src/http_service/http_attachment_service.dart';
import 'package:finance_app/src/http_service/http_services_service.dart';
import 'package:finance_app/src/mixin/check_plan_mixin.dart';
import 'package:finance_app/src/mixin/from_attach_mixin.dart';
import 'package:finance_app/src/mixin/init_edit_data_mixin.dart';
import 'package:finance_app/src/provider/dashboard/products_services/products_and_services_provider.dart';
import 'package:finance_app/src/provider/dashboard/products_services/views/services_provider.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/cash_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/currency_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/list_select_bottom_sheet.dart';
import 'package:flutter/material.dart';

class NewServiceProvider extends BaseProvider
    with FormAttachMixin, InitEditDataMixin, CheckPlanMixin {
  FocusNode nameFocusNode = FocusNode();
  TextEditingController nameController = TextEditingController();

  FocusNode codeFocusNode = FocusNode();
  TextEditingController codeController = TextEditingController();

  FocusNode priceFocusNode = FocusNode();
  TextEditingController priceController = TextEditingController();

  bool isCheckInclusive = false;

  TextEditingController serviceDescController = TextEditingController();
  FocusNode serviceDescFocusNode = FocusNode();

  List<String> menuList = [];

  bool get enable =>
      nameController.text.length > 0 && priceController.text.length > 0;

  bool get showSellPrice => id == null || isEdit || enableSell;
  bool get showBuyPrice => id == null || isEdit || enableBuy;

  @override
  Future get dataFuture => null;

  @override
  void initState() {
    super.initState();
    nameController.addListener(() {
      update();
    });
    priceController.addListener(() {
      update();
    });
  }

  @override
  void dispose() {
    super.dispose();
    codeFocusNode.dispose();
    codeController.dispose();
    nameFocusNode.dispose();
    nameController.dispose();
    sellFocusNode.dispose();
    sellPriceController.dispose();
    buyFocusNode.dispose();
    buyPriceController.dispose();
    serviceDescFocusNode.dispose();
    serviceDescController.dispose();
  }

  void unFocus() {
    priceFocusNode.unfocus();
    nameFocusNode.unfocus();
    sellFocusNode.unfocus();
    buyFocusNode.unfocus();
    serviceDescFocusNode.unfocus();
  }

  /// ***************** Pro *****************  ///

  SettingDataCategory category;
  bool enableSell = false;
  bool isCheckSellInclusive = true;
  SettingDataCurrency sellCurrency;
  SettingDataTax sellGstRate;
  TextEditingController sellPriceController = TextEditingController();
  FocusNode sellFocusNode = FocusNode();

  bool enableBuy = false;
  bool isCheckBuyInclusive = true;
  SettingDataCurrency buyCurrency;
  SettingDataTax buyGstRate;
  TextEditingController buyPriceController = TextEditingController();
  FocusNode buyFocusNode = FocusNode();

  void onChangeSell() {
    unFocus();
    enableSell = !enableSell;
    if (id == null && enableSell == true) {
      sellGstRate = Config.settingInfo.taxData;
    }
    update();
  }

  void onChangeSellInclusive() {
    unFocus();
    isCheckSellInclusive = !isCheckSellInclusive;
    update();
  }

  void onSelectCategory() async {
    unFocus();
    final result = await Routes.navigateTo(
        RouterGenProviders.productsAndServicesCategoryPage,
        params: {
          'type': 'service',
          'categories': categories,
        });
    if (result != null) {
      categories = result;
      update();
    }
  }

  void onChangeSellUnit() {
    unFocus();
    obtainContext?.call((context) async {
      sellCurrency = await showCurrencyBottomSheet(context, sellCurrency);
      update();
    });
  }

  void onChangeSellGstRate() {
    unFocus();
    obtainContext?.call((context) async {
      sellGstRate = await showGstRateBottomSheet(context, sellGstRate);
      update();
    });
  }

  void onChangeBuy() {
    unFocus();
    enableBuy = !enableBuy;
    if (id == null && enableBuy == true) {
      buyGstRate = Config.settingInfo.taxData;
    }
    update();
  }

  void onChangeBuyInclusive() {
    unFocus();
    isCheckBuyInclusive = !isCheckBuyInclusive;
    update();
  }

  void onChangeBuyUnit() {
    unFocus();
    obtainContext?.call((context) async {
      buyCurrency = await showCurrencyBottomSheet(context, buyCurrency);
      update();
    });
  }

  void onChangeBuyGstRate() {
    unFocus();
    obtainContext?.call((context) async {
      buyGstRate = await showGstRateBottomSheet(context, buyGstRate);
      update();
    });
  }

  void onProSave() async {
    unFocus();
    if (codeController.text.length == 0) {
      showToast(S.current.please_enter_the_product_code);
      return;
    }
    if (nameController.text.length == 0) {
      showToast(S.current.please_enter_the_product_name);
      return;
    }

    double sellPrice = double.parse(sellPriceController.text, (e) => null);
    if (enableSell) {
      if (sellGstRate == null && Config.currentCompany.enableGst != 1) {
        sellGstRate = Config.settingInfo.taxData ?? SettingDataTax();
      }
      if (sellGstRate == null) {
        showToast(S.current.please_select_sell_gst_rate);
        return;
      }
    }
    // if (sellPrice == null) {
    //   showToast(S.current.please_enter_the_real_sell_price);
    //   return;
    // }

    double buyPrice = double.parse(buyPriceController.text, (e) => null);
    if (enableBuy) {
      if (buyGstRate == null && Config.currentCompany.enableGst != 1) {
        buyGstRate = Config.settingInfo.taxData ?? SettingDataTax();
      }
      if (buyGstRate == null) {
        showToast(S.current.please_select_buy_gst_rate);
        return;
      }
    }
    // if (buyPrice == null) {
    //   showToast(S.current.please_enter_the_real_buy_price);
    //   return;
    // }

    List<int> attachmentIds = [];
    obtainContext?.call((context) {
      BaseConfig.dialogBase
          .showLoadingDialog(context: context, text: S.current.loading);
    });
    if (files.length > 0) {
      for (final item in files) {
        await post(
            HttpAttachmentService.createAttachment(
              item,
            ), onSuccess: (result) {
          final data = getEntityFromResult<OcrAttachmentEntity>(result);
          attachmentIds.add(data.id);
        });
      }
    }
    if (attachmentIds.length != files.length) {
      showToast(S.current.file_upload_failure);
      obtainContext?.call((context) {
        Navigator.of(context).pop();
      });
      return;
    }

    ServicesEntity entity;
    String errorMsg;
    if (isEdit == true) {
      await post(
          HttpServicesService.updateService(id,
              category_id: null,
              name: nameController.text,
              code: codeController.text,
              description: serviceDescController.text,
              enable_sell: enableSell ? 1 : 0,
              currency_code: sellCurrency?.key,
              price: sellPrice,
              tax_id: sellGstRate?.id,
              is_tax_inclusive: isCheckSellInclusive ? 1 : 0,
              enable_purchase: enableBuy ? 1 : 0,
              purchase_currency_code: buyCurrency?.key,
              purchase_price: buyPrice,
              purchase_tax_id: buyGstRate?.id,
              purchase_is_tax_inclusive: isCheckBuyInclusive ? 1 : 0,
              attachment_ids: attachmentIds,
              categories: categories), onSuccess: (result) {
        entity = getEntityFromResult<ServicesEntity>(result);
      }, onError: (int code, String msg, _, __) {
        errorMsg = msg;
      });
    } else {
      await post(
          HttpServicesService.createService(
              name: nameController.text,
              code: codeController.text,
              description: serviceDescController.text,
              enable_sell: enableSell ? 1 : 0,
              currency_code: sellCurrency?.key,
              price: sellPrice,
              tax_id: sellGstRate?.id,
              is_tax_inclusive: isCheckSellInclusive ? 1 : 0,
              enable_purchase: enableBuy ? 1 : 0,
              purchase_currency_code: buyCurrency?.key,
              purchase_price: buyPrice,
              purchase_tax_id: buyGstRate?.id,
              purchase_is_tax_inclusive: isCheckBuyInclusive ? 1 : 0,
              attachment_ids: attachmentIds,
              categories: categories),
          autoHandler: AutoHandler.Toast, onSuccess: (result) {
        entity = getEntityFromResult<ServicesEntity>(result);
      }, onError: (int code, String msg, _, __) {
        errorMsg = msg;
      });
    }
    obtainContext?.call((context) {
      Navigator.of(context).pop();
    });
    if (entity != null) {
      final provider = Providers.get<ProductsAndServicesProvider>(
          RouterGenProviders.productsAndServicesPage, null);
      if (provider != null) {
        provider.getChildProvider<ServicesProvider>().updateService(entity);
      }

      if (entity != null) {
        obtainContext?.call((context) {
          Navigator.of(context).pop(entity);
        });
      }
    } else {
      obtainContext?.call((context) {
        showGotItTipBottomSheet(context, errorMsg);
      });
    }
  }

  bool isActivate;
  List<String> categories;

  void initService(ServicesEntity data, [String text]) async {
    if (text != null) {
      nameController.text = text;
    }
    if (data == null) {
      sellCurrency = Config.defaultCurrency;
      buyCurrency = Config.defaultCurrency;
      return;
    }
    init(data.id);
    isActivate = data.isActivated == 1;
    codeController.text = data.code;
    nameController.text = data.name;
    categories = data.categories;

    enableSell = data.enableSell == 1;
    if (enableSell == true) {
      sellCurrency = Config.settingData.currency.firstWhere(
          (element) => element.key == data.currencyCode,
          orElse: () => null);
      sellPriceController.text = data.price?.toString();
      sellGstRate = data.tax;
      isCheckSellInclusive = data.isTaxInclusive == 1;
    }
    enableBuy = data.enablePurchase == 1;
    if (enableBuy) {
      buyCurrency = Config.settingData.currency.firstWhere(
          (element) => element.key == data.purchaseCurrencyCode,
          orElse: () => null);
      buyPriceController.text = data.purchasePrice?.toString();
      buyGstRate = data.purchaseTax;
      isCheckBuyInclusive = data.purchaseIsTaxInclusive == 1;
    }
    if (data.isActivated == 1) {
      //显示禁用的菜单
      menuList = ['Edit', 'Delete', 'Deactivate'];
    } else {
      menuList = ['Delete', 'Activate'];
    }
    serviceDescController.text = data.description;
    attachments = data.attachments;
  }

  void onSelectMenu(String value) {
    switch (value) {
      case 'Edit':
        onChangeEditMode();
        break;
      case 'Delete':
        onDelete();
        break;
      case 'Deactivate':
        onDeactivate();
        break;
      case 'Activate':
        onActivate();
        break;
    }
  }

  void onDelete() {
    if (isPlanExpired()) return;

    obtainContext?.call((context) async {
      final result = await showServiceDeleteInfoBottomSheet(context);
      if (result == true) {
        bool isSuccess = false;
        await post(HttpServicesService.deleteService(id),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess) {
          await showServiceDeleteSuccessBottomSheet(context);
          Navigator.of(context).pop({
            'delete': true,
          });
        }
      }
    });
  }

  void onDeactivate() {
    if (isPlanExpired()) return;

    obtainContext?.call((context) async {
      final result = await showServiceDeactivateInfoBottomSheet(context);
      if (result == true) {
        ServicesEntity entity;
        await post(HttpServicesService.deactivateService(id),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          entity = getEntityFromResult<ServicesEntity>(result);
        });
        if (entity != null) {
          await showServiceDeActivatedSuccessBottomSheet(context);
          initService(entity);
          update();
          Providers.get<ProductsAndServicesProvider>(
                  RouterGenProviders.productsAndServicesPage, null)
              ?.getChildProvider<ServicesProvider>()
              ?.updateService(entity);
        }
      }
    });
  }

  void onActivate() async {
    if (isPlanExpired()) return;

    ServicesEntity entity;
    await post(HttpServicesService.activateService(id),
        autoHandler: AutoHandler.Toast,
        loadingTip: S.current.loading, onSuccess: (result) {
      entity = getEntityFromResult<ServicesEntity>(result);
    });
    if (entity != null) {
      obtainContext?.call((context) {
        showServiceActivatedSuccessBottomSheet(context);
      });
      initService(entity);
      update();
      Providers.get<ProductsAndServicesProvider>(
              RouterGenProviders.productsAndServicesPage, null)
          ?.getChildProvider<ServicesProvider>()
          ?.updateService(entity);
    }
  }

  @override
  List<OcrAttachmentEntity> attachments;

  @override
  Future get editDataFuture => dataFuture;

  @override
  TextEditingController get numberCtl => codeController;

  @override
  String get type => 'service';
}
